import {Component, ElementRef, OnInit} from '@angular/core';
import {Storage} from '@ionic/storage';
import {Events, NavController, ToastController} from '@ionic/angular';
import {ActivatedRoute} from '@angular/router';
import {AppConfig} from '../../common/app-config.enum';
import {HttpService} from '../../services/http.service';
import {BasePage} from '../../common/basePage';
import {UrlAndOPT} from '../../common/url-and-opt.enum';

/**
 * 九宫格手势解锁
 */
@Component({
  selector: 'app-gesture-lock',
  templateUrl: './gesture-lock.page.html',
  styleUrls: ['./gesture-lock.page.scss']
})
export class GestureLockPage extends BasePage implements OnInit {

  userInfo: any = {};
  styleWidth = 320;
  styleHeight = 320;
  defaultColor = '#87888a';
  activeColor = '#27AED5';
  dangerColor = '#FF0000';
  successColor = '#2CFF26';
  canvas: HTMLCanvasElement;
  ctx: CanvasRenderingContext2D;
  devicePixelRatio: number; // 屏幕像素比
  touchFlag: boolean; // 开始和结束绘制标记
  r: number;      // 小圆圈半径
  arr = [];       // 全部解锁点的集合
  restPoint: any[] = []; // 未激活点的集合
  lastPoint: any[] = []; // 已激活点的集合
  minPointNo = 4; // 解锁点个数最小限制
  maxInputNo = 5; // 输入次数最大限制
  titleInitList = ['请绘制解锁图案', '请再次输入', '请解锁登录'];
  title: string;
  // 临时密码数据及要进行的步骤
  pswObj: any = {};
  // 储存的手势密码
  lockPassword: any[] = [];
  // 是否允许手势画图
  enable = true;
  // 是否显示密码登录、切换账号等链接
  isShowLink = false;
  // 是否允许离开
  canLeave = false;
  // 是否是因为idSign超时打开解锁
  isTimeout = false;

  constructor(public navCtrl: NavController,
              public toastCtrl: ToastController,
              private activatedRoute: ActivatedRoute,
              private elRef: ElementRef,
              private service$: HttpService,
              private storage: Storage,
              private events: Events
  ) {
    super(navCtrl, toastCtrl);
  }

  async ngOnInit() {
    // 初始化图形界面
    this.initCanvas();
    // 初始化参数
    this.canLeave = (this.activatedRoute.snapshot.params['canLeave'] === 'true'); // 是否可以离开并显示返回按钮
    this.isShowLink = (this.activatedRoute.snapshot.params['isShowLink'] === 'true'); // 是否显示“密码登录”和“切换账号”
    this.isTimeout = (this.activatedRoute.snapshot.params['isTimeout'] === 'true'); // 是否idSign超时
    // 依据参数判断起始步骤
    if (this.activatedRoute.snapshot.params['step']) {
      const step = this.activatedRoute.snapshot.params['step'] * 1;
      if (step === 0) {
        this.pswObj.step = step;
        this.title = this.titleInitList[step];
      }
    } else {
      await this.initData();
    }
    this.userInfo = await this.storage.get(AppConfig.USER_INFO);
    this.getData();
  }

  // 获取用户基础数据
  private getData() {
    this.service$.doRequest(UrlAndOPT.auth_userInfo_func)
      .subscribe(obj => {
        if (obj) {
          // 设置头像图片地址
          this.userInfo['photo'] = this.HOST + obj['photo'];
        }
      });
  }

  // 前往登录页，依据参数判断是否传递账号
  async pushLogin(hasName: boolean) {
    await this.service$.clearUserInfo();
    if (hasName) {
      this.events.publish(AppConfig.TOPIC_MOBILE, {mobile: this.userInfo['mobile']});
    }
    this.canLeave = true;
    await this.navCtrl.pop();
    await this.navCtrl.navigateRoot(['/login']);
  }

  // 根据存储结果设置数据初始状态
  async initData() {
    try {
      this.lockPassword = await this.storage.get(AppConfig.GESTURE_LOCK);
      // 手势解锁图案已存在
      if (this.lockPassword && this.lockPassword.length > this.minPointNo - 1) {
        this.pswObj.step = 2;
        this.title = this.titleInitList[2];
        this.canLeave = false;
      } else {
        this.pswObj.step = 0;
        this.title = this.title = this.titleInitList[0];
      }
    } catch (e) {
      this.title = '图案读取异常，请使用密码登录';
    }
  }

  // 初始化画布
  initCanvas() {
    // 获取画布对象
    this.canvas = this.elRef.nativeElement.getElementsByTagName('canvas')[0];
    // 获取屏幕像素比
    this.devicePixelRatio = (window.devicePixelRatio || 1);
    // 缩放画布
    this.canvas.height = this.styleWidth * this.devicePixelRatio;
    this.canvas.width = this.styleHeight * this.devicePixelRatio;
    // 获取画布2D上下文
    this.ctx = this.canvas.getContext('2d');
    // 创建解锁密码
    this.createCircle();
  }

  // 绘制所有解锁密码小圆圈(重置画布和绘制数据)
  createCircle() {
    // 重置绘制数据
    this.arr = [];
    this.lastPoint = [];
    this.restPoint = [];
    // 根据canvas的大小来平均分配半径
    const n = 3;
    let count = 0;
    this.r = this.canvas.width / (1 + 4 * n);
    // 计算解锁点的坐标
    for (let i = 0; i < n; i++) {
      for (let j = 0; j < n; j++) {
        count++;
        const obj = {
          x: j * 4 * this.r + 2.5 * this.r,
          y: i * 4 * this.r + 2.5 * this.r,
          index: count
        };
        // 储存解锁点坐标和索引值
        this.arr.push(obj);
        this.restPoint.push(obj);
      }
    }
    // 清除画布内容
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    // 遍历绘制解锁密码小圆圈
    for (let i = 0; i < this.arr.length; i++) {
      this.drawCle(this.arr[i].x, this.arr[i].y);
    }
  }

  // 绘制小圆圈
  drawCle(x, y) {
    this.ctx.strokeStyle = this.defaultColor;
    this.ctx.lineWidth = 5;
    this.ctx.beginPath();
    this.ctx.arc(x, y, this.r, 0, Math.PI * 2, true);
    this.ctx.closePath();
    this.ctx.stroke();
  }

  touchstart(e) {
    e.preventDefault(); // 某些android的touchmove不宜触发，所以增加此行代码
    if (this.enable) {
      const po = this.getPosition(e);
      for (let i = 0; i < this.arr.length; i++) {
        if (Math.abs(po.x - this.arr[i].x) < this.r && Math.abs(po.y - this.arr[i].y) < this.r) {
          this.touchFlag = true; // 开启绘制标记
          this.drawPoint(this.activeColor); // 绘制起始点圆心
          this.lastPoint.push(this.arr[i]);
          this.restPoint.splice(i, 1);
          break;
        }
      }
    }
  }

  touchmove(e) {
    if (this.touchFlag) {
      this.update(this.getPosition(e));
    }
  }

  touchend() {
    if (this.touchFlag) {
      this.touchFlag = false; // 关闭绘制标记
      this.enable = false; // 临时禁止手势画图
      this.storePass();
      setTimeout(() => {
        this.createCircle();
        this.enable = true; // 画板数据重新初始化后，再允许画图(防止新旧数据交叉冲突)
      }, 1000);
    }
  }

  // touchend结束之后对密码和状态的处理
  async storePass() {
    if (this.lastPoint.length < this.minPointNo) {
      this.drawStatusPoint(this.dangerColor); // 外圈警告色
      this.drawPoint(this.dangerColor);  // 圆心警告色
      this.drawLine(this.dangerColor, this.lastPoint[this.lastPoint.length - 1]); // 轨迹警告色
      this.title = `请连接至少${this.minPointNo}个点`;
    } else {
      if (this.pswObj.step === 2) { // 解锁登录
        if (this.checkPass(this.lockPassword, this.lastPoint)) {
          this.drawStatusPoint(this.successColor); // 外圈成功色
          this.drawPoint(this.successColor); // 圆心成功色
          this.drawLine(this.successColor, this.lastPoint[this.lastPoint.length - 1]); // 轨迹成功色
          this.title = '解锁成功';
          // 解锁成功后，返回上一页
          this.canLeave = true;
          if (this.isTimeout) {
            this.events.publish(AppConfig.TOPIC_TAB_REFRESH); // 如果idSign超时，解锁成功后通知TAB中的页面刷新数据
          }
          await this.navCtrl.navigateRoot(['/tabs/home']);
        } else {
          // 每输入错误一次，可用次数减1
          this.maxInputNo--;
          if (this.maxInputNo > 0) {
            this.drawStatusPoint(this.dangerColor);
            this.drawPoint(this.dangerColor);
            this.drawLine(this.dangerColor, this.lastPoint[this.lastPoint.length - 1]);
            this.title = `输入错误，您还可以输入${this.maxInputNo}次`;
          } else {
            // 输入次数用尽，清除本地存储的用户信息并跳转至登录页
            this.title = '';
            await this.pushLogin(true);
          }
        }
      } else if (this.pswObj.step === 1) { // 再次设置图案
        if (this.checkPass(this.pswObj['fpassword'], this.lastPoint)) {
          this.lockPassword = this.lastPoint;
          try {
            await this.storage.set(AppConfig.GESTURE_LOCK, this.lockPassword);
            this.pswObj.step = 2;
            this.drawStatusPoint(this.successColor);
            this.drawPoint(this.successColor);
            this.drawLine(this.successColor, this.lastPoint[this.lastPoint.length - 1]);
            this.title = '图案保存成功，请解锁登录';
            this.canLeave = false;
            this.events.publish(AppConfig.TOPIC_UNDO_LIST);
            // console.log(this.lockPassword.map(p => p.index));
          } catch (e) {
            this.title = '图案保存失败，请重新设置';
            delete this.pswObj.step;
          }
        } else {
          this.drawStatusPoint(this.dangerColor);
          this.drawPoint(this.dangerColor);
          this.drawLine(this.dangerColor, this.lastPoint[this.lastPoint.length - 1]);
          this.title = '图案不一致，请重新输入';
          delete this.pswObj.step;
        }
      } else { // 首次设置图案
        this.pswObj.step = 1;
        this.pswObj['fpassword'] = this.lastPoint; // 纪录首次设置的密码
        this.title = this.titleInitList[1];
      }
    }
  }

  // 检测密码
  checkPass(psw1, psw2) {
    const p1 = psw1.map(ps1 => ps1.index).toString();
    const p2 = psw2.map(ps2 => ps2.index).toString();
    return p1 === p2;
  }

  // 获取touch点相对于canvas的坐标
  getPosition(e): any {
    // canvas相对于视窗的位置集合(有top, right, bottom, left等属性，以像素为单位)
    const rect = e.currentTarget.getBoundingClientRect();
    // 返回相对位置信息
    return {
      x: (e.touches[0].clientX - rect.left) * this.devicePixelRatio,
      y: (e.touches[0].clientY - rect.top) * this.devicePixelRatio
    };
  }

  // 核心变换方法(touchmove事件调用)
  update(po) {
    // 每帧清除画布
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    // 每帧先把面板画出来
    for (let i = 0; i < this.arr.length; i++) { //
      this.drawCle(this.arr[i].x, this.arr[i].y);
    }
    this.drawPoint(this.activeColor);        // 每帧重画轨迹上的圆心
    this.drawStatusPoint(this.activeColor);  // 每帧重画轨迹上的小圆圈
    this.drawLine(this.activeColor, po);     // 每帧画轨迹线条
    // 是否经过了未激活点，如果经过则绘制圆心
    for (let i = 0; i < this.restPoint.length; i++) {
      if (Math.abs(po.x - this.restPoint[i].x) < this.r && Math.abs(po.y - this.restPoint[i].y) < this.r) {
        this.drawPoint(this.activeColor);
        this.lastPoint.push(this.restPoint[i]);
        this.restPoint.splice(i, 1);
        break;
      }
    }
  }

  // 绘制touch轨迹上的圆心
  drawPoint(fillStyle) {
    for (let i = 0; i < this.lastPoint.length; i++) {
      this.ctx.fillStyle = fillStyle;
      this.ctx.beginPath();
      this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r / 2.5, 0, Math.PI * 2, true);
      this.ctx.closePath();
      this.ctx.fill();
    }
  }

  // 绘制touch轨迹上的小圆圈
  drawStatusPoint(strokeStyle) {
    for (let i = 0; i < this.lastPoint.length; i++) {
      this.ctx.strokeStyle = strokeStyle;
      this.ctx.beginPath();
      this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r, 0, Math.PI * 2, true);
      this.ctx.closePath();
      this.ctx.stroke();
    }
  }

  // 每一帧绘制解锁轨迹
  drawLine(strokeStyle, po) {
    this.ctx.beginPath();
    this.ctx.strokeStyle = strokeStyle; // 轨迹颜色
    this.ctx.lineWidth = 5; // 轨迹宽度
    this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y);

    for (let i = 1; i < this.lastPoint.length; i++) {
      this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y);
    }
    this.ctx.lineTo(po.x, po.y);
    this.ctx.stroke();
    this.ctx.closePath();
  }

}
